import {track, trigger} from "./effects.js";
import {hasChanged, isArray, isObject} from "./utils.js";
import {reactive} from "./reactive.js";

export function ref(value) {
  return createRef(value)
}

export function shallowRef(value) {
  return createRef(value, true)
}

function createRef(rawValue, shallow) {
  return new RefImpl(rawValue, shallow)
}

const convert = value => isObject(value) ? reactive(value) : value;

class RefImpl {
  _value;
  __v_isRef = true;

  constructor(rawValue, shallow) {
    this.rawValue = rawValue;
    this.shallow = shallow;
    this._value = shallow ? rawValue : convert(rawValue);
  }

  get value() {
    track(this, 'get', 'value');
    return this._value;
  }

  set value(newValue) {
    if (hasChanged(newValue, this.rawValue)) {
      this.rawValue = newValue;
      this._value = this.shallow ? newValue : convert(newValue);
    }
    trigger(this, 'set', 'value', newValue);
  }
}

export function toRef(target, key) {
  return new ObjectRefImpl(target, key)
}

class ObjectRefImpl {
  _v_isRef = true;
  constructor(target, key) {
    this.target = target;
    this.key = key;
  }

  get value() {
    return this.target[this.key];
  }
  set value(newValue) {
    this.target[this.key] = newValue;
  }
}
export function toRefs(obj) {
  const res = isArray(obj) ? new Array(obj.length) : {};
  for (const resKey in obj) {
    res[resKey] = toRef(obj, resKey);
  }
}

